//  Dialecto
//  dialecto.js

Dialecto = {
}

// Base Element
Dialecto.Element = function () {
};
Dialecto.Element.prototype = p = Node.prototype;

p.separator = new Size2D (7, 7);

p.drawAt = function (ctx, x, y) {
	ctx.translate(x, y);
	this.draw(ctx);
	ctx.translate(-x, -y);
};

// Assignment
Dialecto.Assignment = function (left, right) {
	this.left = left;
	this.right = right;
};

Dialecto.Assignment.prototype = p = new Dialecto.Element();

p.draw = function (ctx) {
	var size = this.getSize(ctx);
	var x = -size.width / 2;
	ctx.fillText(this.left, x);
	x += ctx.measureText(this.left).width;
	x += this.separator.width;
	ctx.drawArrow(x, size.height / 2, x + this.arrowSize.width, size.height / 2, this.arrowWeight, this.arrowColor);
	x += this.arrowSize.width;
	x += this.separator.width;
	ctx.fillText(this.right, x);
};

p.getSize = function (ctx) {
	return ctx.measureText(this.left)
		.addHorizontally (this.separator)
		.addHorizontally (this.arrowSize)
		.addHorizontally (this.separator)
		.addHorizontally (ctx.measureText(this.right));
};

p.arrowSize = new Size2D (20, 9);
p.arrowWeight = 9;
p.arrowColor = "white";

// Sequence
Dialecto.Sequence = function () {
	this.elements = [];
};

Dialecto.Sequence.prototype = p = new Dialecto.Element();

p.add = function (element) {
	this.elements.push (element);
};

p.draw = function (ctx) {
	var y = 0;
	for (i in this.elements) {
		var element = this.elements[i];
		var height = element.getSize(ctx).height + this.separator.height;
		element.draw(ctx);
		ctx.translate(0, height);
		y += height;
	}
	ctx.translate (0, -y);
};

p.getSize = function (ctx) {
	var size = this.separator.copy();
	for (i in this.elements) {
		var element = this.elements[i];
		size.addVertically (element.getSize(ctx)).addVertically(this.separator);
	}
	return size.addHorizontally(this.separator, 2);
};

// If
Dialecto.If = function (condition) {
	this.condition = condition;
	this.left = new Dialecto.Sequence();
	this.right = new Dialecto.Sequence();
};

Dialecto.If.prototype = p = new Dialecto.Element();

p.draw = function (ctx) {
	var conditionSize = ctx.measureText(this.condition);
	var topSize = this.separator.copy().addVertically(conditionSize, 2);
	var size = this.getSize(ctx);
	var leftSize = this.left.getSize(ctx);
	ctx.beginPath();
	ctx.moveTo(0, 0);
	
	
	ctx.lineTo(size.width / 2, topSize.height);
	ctx.lineTo(size.width / 2, size.height);
	ctx.lineTo(-size.width / 2, size.height);
	ctx.lineTo(-size.width / 2, topSize.height);
	ctx.closePath();
	ctx.fill ();
	ctx.moveTo(-size.width / 2, topSize.height);
	ctx.lineTo(size.width / 2, topSize.height);
	ctx.moveTo(-size.width / 2 + leftSize.width, topSize.height);
	ctx.lineTo(-size.width / 2 + leftSize.width, size.height);
	ctx.stroke ();
	ctx.fillText (this.condition, -conditionSize.width / 2, conditionSize.height);
	topSize.addVertically(this.separator);
	this.left.drawAt (ctx, (-size.width + leftSize.width) / 2, topSize.height);
	this.right.drawAt (ctx, leftSize.width / 2, topSize.height);
};

p.getSize = function (ctx) {
	return this.left.getSize(ctx)
		.addHorizontally (this.right.getSize(ctx))
		.addVertically (ctx.measureText(this.condition), 2)
		.addVertically (this.separator);
};

//While
Dialecto.While = function (condition) {
	this.condition = condition;
	this.sequence = new Dialecto.Sequence();
};
Dialecto.While.prototype = p = new Dialecto.Element();

p.draw = function (ctx) {
	var conditionSize = ctx.measureText(this.condition);
	var topSize = this.separator.copy().addVertically(conditionSize, 2);
	var size = this.getSize(ctx);
	ctx.beginPath();
	ctx.moveTo(-size.width / 2, 0);
	ctx.lineTo(size.width / 2, 0);
	ctx.lineTo(size.width / 2, size.height);
	ctx.lineTo(-size.width / 2, size.height);
	ctx.moveTo(-size.width / 2, topSize.height);
	ctx.lineTo(size.width / 2, topSize.height);
	ctx.stroke ();
	ctx.fillText (this.condition, -conditionSize.width / 2, conditionSize.height);
	topSize.addVertically(this.separator);
	this.sequence.drawAt (ctx, 0, topSize.height);
};

p.getSize = function (ctx) {
	var size = 
	this.sequence.getSize(ctx)
		.addVertically (ctx.measureText(this.condition), 2)
		.addVertically (this.separator);
	return size;
	
};

//For
Dialecto.For = function (counter, begin, end) {
	this.iterator = new Dialecto.Iterator(counter, begin, end);
	this.sequence = new Dialecto.Sequence();
};

Dialecto.For.prototype = p = new Dialecto.Element();

p.draw = function (ctx) {
	var iteratorSize = this.iterator.getSize(ctx);
	var size = this.getSize(ctx);
		
	ctx.beginPath();
	ctx.moveTo((iteratorSize.width - size.width)/2, 0);
	ctx.lineTo(size.width/2, 0);
	ctx.lineTo(size.width/2, size.height);
	ctx.lineTo((iteratorSize.width - size.width)/2, size.height);
	ctx.lineTo((iteratorSize.width - size.width)/2, (size.height + iteratorSize.height) / 2);
	ctx.moveTo((iteratorSize.width - size.width)/2, (size.height - iteratorSize.height) / 2);
	ctx.lineTo((iteratorSize.width - size.width)/2, 0);
	//ctx.fill ();
	ctx.stroke();
	this.sequence.drawAt (ctx, iteratorSize.width / 2, 0);
	this.iterator.drawAt (ctx, (iteratorSize.width - size.width)/2, (size.height - iteratorSize.height) / 2);
};

p.getSize = function (ctx) {
	return this.sequence.getSize(ctx)
		.addHorizontally(this.iterator.getSize(ctx))
		.addHorizontally(this.separator, 4)
		.addVertically(this.separator, 2);
};


//For.Iterator
Dialecto.Iterator = function (counter, begin, end) {
	this.counter = counter;
	this.begin = begin;
	this.end = end;
};

Dialecto.Iterator.prototype = p = new Dialecto.Element();

p.draw = function (ctx) {
	var size = this.getSize(ctx);
	var radius = size.width/2;
	var counterSize = ctx.measureText(this.counter);
	var beginSize = ctx.measureText(this.begin);
	var endSize = ctx.measureText(this.end);
	
	ctx.beginPath();
	
	ctx.circle(0,radius,radius);
	ctx.moveTo(-radius,radius);
	ctx.lineTo(radius,radius);
	ctx.moveTo(0,radius);
	ctx.lineTo(0,size.width);
	
	ctx.stroke();

	ctx.fillText (this.counter, -counterSize.width / 2, radius - counterSize.height - this.separator.height);
	ctx.fillText (this.begin, -(radius + beginSize.width)/2, radius + this.separator.height);
	ctx.fillText (this.end, (radius - endSize.width)/2, radius + this.separator.height);
	
};

p.getSize = function (ctx) {
	var width = Math.max(ctx.measureText(this.counter).width, Math.max(ctx.measureText(this.begin).width, ctx.measureText(this.end).width) * 2) +
		this.separator.width * 4;
	return new Size2D(width, width);
};


